﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Networking
{
    /// <summary>
    /// Represents an immutable coordinate
    /// </summary>
    public class Coords
    {

        /// <summary>
        /// The X coord
        /// </summary>
        public short X { get; private set; }
        
        /// <summary>
        /// The Y coord
        /// </summary>
        public short Y { get; private set; }

        /// <summary>
        /// Creates a new instance of Coords specifying both the coordinates
        /// </summary>
        /// <param name="X">The X coord</param>
        /// <param name="Y">The Y coord</param>
        public Coords(short X, short Y)
        {
            this.X = X;
            this.Y = Y;
        }

    }

    /// <summary>
    /// Packet of type FramebufferUpdateRequestPacket, a framebuffer update request 
    /// </summary>
    public class FramebufferUpdateRequestPacket : Packet
    {

        /// <summary>
        /// The request incremental number
        /// </summary>
        public byte Incremental  { get; private set; }
        
        /// <summary>
        /// The coordinates of left-upper corner of the framebuffer update area
        /// </summary>
        public Coords Position  { get; private set; }
        
        /// <summary>
        /// The size of the update area
        /// </summary>
        public Size Size        { get; private set; }

        /// <summary>
        /// Creates a new instance of FramebufferUpdateRequestPacket specifying all the parameters
        /// </summary>
        /// <param name="Incremental">The request incremental number</param>
        /// <param name="Position">The coordinates of left-upper corner of the framebuffer update area</param>
        /// <param name="Size">The size of the update area</param>
        public FramebufferUpdateRequestPacket(byte Incremental, Coords Position, Size Size)
            : base(PacketType.FramebufferUpdateRequest)
        {
            this.Incremental = Incremental;
            this.Position = Position;
            this.Size = Size;
        }

        /// <summary>
        /// Creates a new instance of FramebufferUpdateRequestPacket extracting all the parameters from the byte buffer
        /// </summary>
        /// <param name="buffer">The byte buffer containing the packet data</param>
        public FramebufferUpdateRequestPacket(byte[] buffer) 
            : base(PacketType.FramebufferUpdateRequest, buffer)
        {
            //
        }

        /// <summary>
        /// Serializes the packet in order to send it
        /// </summary>
        /// <returns>The bytes of the packet</returns>
        public override byte[] Serialize()
        {
            MemoryStream memory = new MemoryStream();

            BinaryWriter writer = new BinaryWriter(memory);

            writer.Write((byte)this.Type);

            writer.Write(this.Incremental);

            writer.Write(this.Position.X);
            writer.Write(this.Position.Y);

            writer.Write(this.Size.Width);
            writer.Write(this.Size.Height);

            writer.Close();

            return memory.ToArray();

        }


        /// <summary>
        /// Loads a packet from a byte buffer
        /// </summary>
        /// <param name="buffer">The data buffer</param>
        public override void Load(byte[] buffer)
        {
            if (buffer.Length != 10) throw new BufferSizeMismatchException(10);

            MemoryStream memory = new MemoryStream(buffer);

            BinaryReader reader = new BinaryReader(memory);

            this.Type = (PacketType)reader.ReadByte();

            if (this.Type != PacketType.FramebufferUpdateRequest) 
                throw new PacketTypeMismatchException(PacketType.FramebufferUpdateRequest, this.Type);

            this.Incremental = reader.ReadByte();

            this.Position = new Coords(reader.ReadInt16(), reader.ReadInt16());

            this.Size = new Size(reader.ReadInt16(), reader.ReadInt16());

            reader.Close();

        }
    }
}
